package gwtappcontainer.server.apis.content;

import gwtappcontainer.server.apis.APIBase;
import gwtappcontainer.server.apis.APIException;
import gwtappcontainer.server.apis.admin.AdminAPI;
import gwtappcontainer.server.apis.admin.Roles;
import gwtappcontainer.server.apis.admin.Roles.Role;
import gwtappcontainer.shared.apis.APIResponse;
import gwtappcontainer.shared.apis.APIResponse.Status;
import gwtappcontainer.shared.apis.admin.RoleProp;
import gwtappcontainer.shared.apis.content.ContentProp;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import javax.inject.Named;

import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiMethod;
import com.google.api.server.spi.config.ApiMethod.HttpMethod;
import com.google.appengine.api.users.User;
import com.google.gson.Gson;

@Api (name = "content", 
	scopes = { "https://www.googleapis.com/auth/userinfo.email" }
)
public class ContentAPI extends APIBase {
	
	private Logger logger = Logger.getLogger(ContentAPI.class.getName());
		
	@ApiMethod(path="setcontent", httpMethod = HttpMethod.PUT)
	public APIResponse setContent(@Named("content_html") String html, 
			@Named("tag") String tag, @Named("publish") boolean publish, User user) {
		
		try {
			
			//content admin for this tag or portal admin can set content
			String contentAdminRole = getContentAdminRoleForTag(tag);
			gateKeeper.ensureRole(user, contentAdminRole, 
					Role.PORTAL_ADMIN.toString());
			
			//ensure tag is valid
			if (false == isValidTag(tag))
				throw new APIException(Status.ERROR_RESOURCE_DOES_NOT_EXIST, 
						"[" + tag + "] is not valid");
						
			ContentRepository repository = new ContentRepository();
			
			ContentProp prop = repository.setContent(html, tag, publish);								
			
			return new APIResponse(Status.SUCCESS, prop);
			
		} catch (Exception ex) {
			return new APIResponse(ex);
		}
	}
	
	@ApiMethod(path="getcontent", httpMethod = HttpMethod.GET)
	public APIResponse getContent(@Named("tag") String tag, User user) {
		try {
			
			ContentRepository repository = new ContentRepository();
			ContentProp prop = repository.getContent(tag);
						
			logger.info("received getContent for tag - " + tag);
			
			if (null == prop)
				throw new APIException(Status.ERROR_RESOURCE_DOES_NOT_EXIST, 
						"Either tag [" + tag + 
						"] is invalid or there is no content for this tag");
			
			//if publish is true anyone can view content, otherwise only valid users
			if (prop.publish == false)
				gateKeeper.ensureValidUser(user);
						
			logger.info("returning content - " + new Gson().toJson(prop));
												
			return new APIResponse(Status.SUCCESS, prop);						
			
		} catch (Exception ex) {
			return new APIResponse(ex);
		}
	}		
	
	@ApiMethod(path="assignuserascontentadmin", httpMethod = HttpMethod.PUT)
	public APIResponse assignUserAsContentAdmin(@Named("email") String email, 
			@Named("tag") String tag, User user) {
		
		try {											
			AdminAPI adminAPI = new AdminAPI();
			String role = getContentAdminRoleForTag(tag);
			
			APIResponse resp = adminAPI.assignRoleToUser(email, role, user);
			
			return resp;
			
		} catch (Exception ex) {
			return new APIResponse(ex);
		}
	}
	
	@ApiMethod(path="addnewtag", httpMethod = HttpMethod.PUT)
	public APIResponse addNewTag(@Named("content_tag") String tag, User user) {
		
		try {					
			//only DEVELOPER can add tag
			ensureRole(user, Role.DEVELOPER);	
			
			AdminAPI adminAPI = new AdminAPI();
			String role = getContentAdminRoleForTag(tag);
			APIResponse resp = adminAPI.addRole(role, user);
			
			return resp;						
		} catch (Exception ex) {
			return new APIResponse(ex);
		}
	}
	
	@ApiMethod(path="getalltags", httpMethod = HttpMethod.GET)
	public APIResponse getAllTags() {
		
		try {	
			AdminAPI adminAPI = new AdminAPI();
			APIResponse resp = adminAPI.getAllRoles();
			
			@SuppressWarnings("unchecked")
			List<RoleProp> roles = (List<RoleProp>) resp.object;
			
			List<String> tags = getTagsFromRoles(roles);
			
			resp.statusCode = Status.SUCCESS;
			resp.object = tags;
			resp.userFriendlyMessage = "No of tags = " + tags.size();
			
			return resp;
							
		} catch (Exception ex) {
			return new APIResponse(ex);
		}
	}
	
	@ApiMethod(path="getallpublishedcontents", httpMethod = HttpMethod.GET)
	public APIResponse getAllValidPublishedContents() {
		
		try {
			ContentRepository repository = new ContentRepository();
			
			Map<String, String> published = repository.getAllValidPublishedContents();
			
			APIResponse response = new APIResponse(Status.SUCCESS, published);
			
			return response;								
		} catch (Exception ex) {
			return new APIResponse(ex);
		}
	}
	
	private boolean isValidTag(String tag) {
		APIResponse resp = getAllTags();
		if (resp.statusCode != Status.SUCCESS)
			return false;
		
		@SuppressWarnings("unchecked")
		List<String> roles = (List<String>) resp.object;
		
		boolean valid = roles.contains(tag.toUpperCase());
		
		return valid;			
	}
	
	private String getContentAdminRoleForTag(String tag) {
		String role = Roles.CONTENT_ADMIN_PREFIX + tag.toUpperCase();
		return role;
	}
	
	private List<String> getTagsFromRoles(List<RoleProp> roles) {
		List<String> tags = new ArrayList<String>();
		for (RoleProp roleProp : roles) {
			String prefix = Roles.CONTENT_ADMIN_PREFIX.toUpperCase();
			if (roleProp.name.startsWith(prefix)) {
				String tag = roleProp.name.substring(prefix.length());
				tags.add(tag);
			}
		}
		
		return tags;
	}
}
